﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using ecdl.demo.model.expression;
using System.Xml.Serialization;
using System.Xml;

namespace ecdl.demo.model.expression {
    public class FontExpression : ParagraphExistsExpression {
        private static readonly string POS_FONTNAME = "Die Schriftart ist korrekt.";
        private static readonly string NEG_FONTNAME = "Die Schriftart ist nicht korrekt.";

        private static readonly string POS_FONTSIZE = "Die Schriftgröße ist korrekt.";
        private static readonly string NEG_FONTSIZE = "Die Schriftgröße ist nicht korrekt.";

        public String FontName { get; set; }
        public Double FontSize { get; set; }

        public FontExpression() {
            FontSize = Double.NaN;
        }

        protected override ExpressionState Evaluate(IEnumerable<OpenXmlElement> contextElements) {
            MultiExpressionState expression = new MultiExpressionState(this);
            expression.IsOk = false;
            foreach (var paragraph in GetAllParagraphs(contextElements)) {
                if (RegexMatches(paragraph)) {
                    bool bothSuccessful = true;
                    if (FontName != null) {
                        ExpressionState state = FontMatches(paragraph);
                        expression.ChildExpressions.Add(state);
                        bothSuccessful &= state.IsOk;
                    }
                    if (!FontSize.Equals(Double.NaN)) {
                        ExpressionState state = FontSizeMatches(paragraph);
                        expression.ChildExpressions.Add(state);
                        bothSuccessful &= state.IsOk;
                    }
                    expression.IsOk = bothSuccessful;
                    return expression;
                }
            }
            return Fail("Der Absatz konnte nicht gefunden werden.");
        }

        private ExpressionState FontMatches(Paragraph paragraph) {
            IEnumerable<RunFonts> runFonts = paragraph.Descendants<RunFonts>();
            foreach (var font in runFonts) {
                if (font.Ascii != FontName) {
                    return Fail(NEG_FONTNAME, POS_FONTNAME);
                }
            }
            return Success(POS_FONTNAME, NEG_FONTNAME);
        }

        private ExpressionState FontSizeMatches(Paragraph paragraph) {
            IEnumerable<FontSize> fontSizes = paragraph.Descendants<FontSize>();
            foreach (var fontSize in fontSizes) {
                double size;
                if (Double.TryParse(fontSize.Val.Value, out size)) {
                    size /= 2;  //take half
                    if (!size.Equals(FontSize)) {
                        return Fail(NEG_FONTSIZE, POS_FONTSIZE);
                    }
                }
            }
            return Success(POS_FONTSIZE, NEG_FONTSIZE);
        }
    }

    public class FontExpressionDTO : ExpressionDTO {
        [XmlAttribute("regex")]
        public string Regex { get; set; }
        [XmlAttribute("fontName")]
        public string FontName { get; set; }
        [XmlAttribute("fontSize")]
        public int FontSize { get; set; }

        public FontExpressionDTO() : base(typeof(FontExpression)) {
        }
    }
}
